﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataModel
{
    public class TermSet : List<Term>
    {
        private String id = GUID.get();
        protected String name;
        protected Boolean isRoot = false;
        public Boolean IsOpenForTermCreation { get; set; }
        public Group Group { get; set; }
        public PropertyCollection SharedCustomProperties = new PropertyCollection();
        public String Description { get; set; }

        public String Name 
        { 
            get { return name; }
            set { name = value; }
        }
        public String ID { get { return id; } set { id = value; } }

        /// <summary>
        /// Initializes a new instance of the <see cref="TermSet"/> class.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="id">The identifier.</param>
        /// <param name="group">The group.</param>
        /// <param name="desc">The description.</param>
        public TermSet(String name, String id = null, String group = "", String desc = "")
        {
            isRoot = true;
            this.name = name;
            this.id = (id != null) ? id : GUID.get();
            Description = desc;
            Group = SaveFile.defaultSCGroup;
            IsOpenForTermCreation = false;
        }

        protected TermSet() { }

        /// <summary>
        /// Adds the root term. Used to create top level terms in a term set.
        /// </summary>
        /// <param name="termName">Name of the term.</param>
        /// <param name="id">The identifier.</param>
        /// <param name="desc">The desc.</param>
        /// <returns></returns>
        public Term AddRootTerm(String termName, String id = null, String desc = "")
        {
            Term t = new Term(termName, 1, true, this, this, desc);
            t.id = (id != null) ? id : GUID.get();
            base.Add(t);
            return t;
        }

        /// <summary>
        /// Gets a term by name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        public Term getTermByName(String name)
        {
            foreach (Term t in this)
            {
                Term t2 = t.getTermByName(name);
                if (t2 != null) { return t2; }
            }
            return null;
        }

        /// <summary>
        /// Gets a term by identifier.
        /// </summary>
        /// <param name="id">The identifier.</param>
        /// <returns></returns>
        public Term getTermById(String id)
        {
            foreach (Term t in this)
            {
                Term t2 = t.getTermById(id);
                if (t2 != null) { return t2; }
            }
            return null;
        }

        /// <summary>
        /// Determines whether this instance has children.
        /// </summary>
        /// <returns></returns>
        public Boolean hasChildren()
        {
            return (this.Count > 0);
        }

        /// <summary>
        /// Deletes all child terms.
        /// </summary>
        public void DeleteAllChildTerms()
        {
            while (hasChildren())
            {
                if (this.ElementAt(0).IsReferencedByASiteColumn())
                {
                    this.ElementAt(0).RemoveSitecolumnReferences();
                }

                if (this.ElementAt(0).hasChildren())
                {
                    this.ElementAt(0).DeleteAllChildTerms();
                }
                this.Remove(this.ElementAt(0));
            }
        }

        /// <summary>
        /// Determines whether this [contains] [the specified name].
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        public bool Contains(String name)
        {
            foreach (Term t in this)
            {
                if (t.Name == name)
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Gets the children in a flat list.
        /// </summary>
        /// <returns></returns>
        public String GetChildrenFlat()
        {
            StringBuilder sb = new StringBuilder();

            foreach (Term t in this)
            {
                sb.Append(t.Name).AppendLine();
                sb.Append(t.GetChildrenFlat());
            }

            return sb.ToString();
        }

        /// <summary>
        /// Counts the child terms.
        /// </summary>
        /// <returns></returns>
        public int termCount()
        {
            int i = 1;
            foreach (TermSet t in this)
            {
                i += t.termCount();
            }
            return i;
            
        }
    }
}
